package br.com.wai2008.socket.service;

import java.util.ArrayList;
import java.util.List;

import comum.Localizacao;

import servidor.localizacao.ILocalizacao;
import servidor.localizacao.LocalizacaoWAI;

import br.com.wai2008.socket.dataobject.WAINetworkObject;
import br.com.wai2008.socket.dataobject.WAIServiceObject;
import br.com.wai2008.socket.protocol.ClientToServerDefaultMessages;
import br.com.wai2008.socket.protocol.ClientToServerProtocol;
import br.com.wai2008.socket.protocol.ServerToServerProtocol;

/**
 * This class implements the protocol definitions to build messages
 * and parse returned messages in data objects for WAI Service.
 * 
 * @since 
 * 		October, 2008.
 * 
 * @version
 * 		WAI2008 - version 1.0
 * 
 * @author 
 * 		Andre Romero Goncales
 */
public class WAIProtocolManipulation {

	/**
	 * Parse the message from client to the WAIServiceObject Data Object.<br>
	 *  
	 * @see 
	 * 		br.com.wai2008.socket.protocol.ClientToServerProtocol
	 * @see 
	 * 		br.com.wai2008.socket.dataobject.WAIServiceObject
	 * 
	 * @param
	 * 		clientMessage message received from client.
	 * 		This message is in a ClientToServerProtocol protocol.
	 * 
	 * @return
	 * 		<b>WAIServiceObject</b> data object or<br>
	 * 		<b>null</b> if an error occur while parse the client message.
	 */
	public static WAIServiceObject getDataObjectFromClientMessage(String clientMessage) {
		System.out.println("[WAIProtocolManipulation] Getting Data Object from Client Message...");
		if (clientMessage != null) {		
			WAIServiceObject dataObject = new WAIServiceObject();
			
			boolean simulation = Boolean.parseBoolean(clientMessage.substring(clientMessage.indexOf(
									ClientToServerProtocol.TAG_CS_SIMULATION_START) + 
									ClientToServerProtocol.TAG_CS_SIMULATION_START.length(), 
									clientMessage.indexOf(ClientToServerProtocol.TAG_CS_SIMULATION_END)
									));
			
			String hdSerial = clientMessage.substring(clientMessage.indexOf(
					ClientToServerProtocol.TAG_CS_HDSERIAL_START) + 
					ClientToServerProtocol.TAG_CS_HDSERIAL_START.length(), 
					clientMessage.indexOf(ClientToServerProtocol.TAG_CS_HDSERIAL_END)
					);
			
			if (!simulation) {
				System.out.println("[WAIProtocolManipulation] THREAD IS NOT SIMULATION...");
				List<WAINetworkObject> networks = new ArrayList<WAINetworkObject>();
				
				while (clientMessage.contains(ClientToServerProtocol.TAG_CS_NETWORK_START)) {
					clientMessage = clientMessage.substring(clientMessage.indexOf(
									ClientToServerProtocol.TAG_CS_NETWORK_START) + 
									ClientToServerProtocol.TAG_CS_NETWORK_START.length());
					String id = clientMessage.substring(clientMessage.indexOf(
							ClientToServerProtocol.TAG_CS_ID_START) + 
							ClientToServerProtocol.TAG_CS_ID_START.length(), 
							clientMessage.indexOf(ClientToServerProtocol.TAG_CS_ID_END)
							);
					
					double signal = Double.parseDouble(clientMessage.substring(clientMessage.indexOf(
							ClientToServerProtocol.TAG_CS_SIGNAL_START) + 
							ClientToServerProtocol.TAG_CS_SIGNAL_START.length(), 
							clientMessage.indexOf(ClientToServerProtocol.TAG_CS_SIGNAL_END)
							));
					
					clientMessage = clientMessage.substring(clientMessage.indexOf(
							ClientToServerProtocol.TAG_CS_NETWORK_END) + 
							ClientToServerProtocol.TAG_CS_NETWORK_END.length());
					
					WAINetworkObject networkDataObject = new WAINetworkObject(id, signal);
					networks.add(networkDataObject);
				}

				String target = clientMessage.substring(clientMessage.indexOf(
						ClientToServerProtocol.TAG_CS_TARGET_START) + 
						ClientToServerProtocol.TAG_CS_TARGET_START.length(), 
						clientMessage.indexOf(ClientToServerProtocol.TAG_CS_TARGET_END)
						);

				int floor = Integer.parseInt(clientMessage.substring(clientMessage.indexOf(
										ClientToServerProtocol.TAG_CS_FLOOR_START) + 
										ClientToServerProtocol.TAG_CS_FLOOR_START.length(), 
										clientMessage.indexOf(ClientToServerProtocol.TAG_CS_FLOOR_END)
										));

				int restriction = Integer.parseInt(clientMessage.substring(clientMessage.indexOf(
										ClientToServerProtocol.TAG_CS_RESTRICTION_START) + 
										ClientToServerProtocol.TAG_CS_RESTRICTION_START.length(), 
										clientMessage.indexOf(ClientToServerProtocol.TAG_CS_RESTRICTION_END)
										));

				String language = clientMessage.substring(clientMessage.indexOf(
						ClientToServerProtocol.TAG_CS_LANGUAGE_START) + 
						ClientToServerProtocol.TAG_CS_LANGUAGE_START.length(), 
						clientMessage.indexOf(ClientToServerProtocol.TAG_CS_LANGUAGE_END)
						);

				dataObject.setSimulation(simulation);
				dataObject.setHdSerial(hdSerial);
				dataObject.setNetwork(networks.toArray(new WAINetworkObject[networks.size()]));
				dataObject.setTargetName(target);
				dataObject.setFloor(floor);
				dataObject.setRestriction(restriction);
				dataObject.setLanguage(language);
				
			} else {
				System.out.println("[WAIProtocolManipulation] THREAD IS SIMULATION...");
				double x = Double.parseDouble(clientMessage.substring(clientMessage.indexOf(
						ClientToServerProtocol.TAG_CS_X_START) + 
						ClientToServerProtocol.TAG_CS_X_START.length(), 
						clientMessage.indexOf(ClientToServerProtocol.TAG_CS_X_END)
						));

				double y = Double.parseDouble(clientMessage.substring(clientMessage.indexOf(
						ClientToServerProtocol.TAG_CS_Y_START) + 
						ClientToServerProtocol.TAG_CS_Y_START.length(), 
						clientMessage.indexOf(ClientToServerProtocol.TAG_CS_Y_END)
						));

				int floor = Integer.parseInt(clientMessage.substring(clientMessage.indexOf(
										ClientToServerProtocol.TAG_CS_FLOOR_START) + 
										ClientToServerProtocol.TAG_CS_FLOOR_START.length(), 
										clientMessage.indexOf(ClientToServerProtocol.TAG_CS_FLOOR_END)
										));
				
				ILocalizacao initialLocalization = new LocalizacaoWAI(x, y, floor);

				String target = clientMessage.substring(clientMessage.indexOf(
						ClientToServerProtocol.TAG_CS_TARGET_START) + 
						ClientToServerProtocol.TAG_CS_TARGET_START.length(), 
						clientMessage.indexOf(ClientToServerProtocol.TAG_CS_TARGET_END)
						);

				int restriction = Integer.parseInt(clientMessage.substring(clientMessage.indexOf(
										ClientToServerProtocol.TAG_CS_RESTRICTION_START) + 
										ClientToServerProtocol.TAG_CS_RESTRICTION_START.length(), 
										clientMessage.indexOf(ClientToServerProtocol.TAG_CS_RESTRICTION_END)
										));

				String language = clientMessage.substring(clientMessage.indexOf(
						ClientToServerProtocol.TAG_CS_LANGUAGE_START) + 
						ClientToServerProtocol.TAG_CS_LANGUAGE_START.length(), 
						clientMessage.indexOf(ClientToServerProtocol.TAG_CS_LANGUAGE_END)
						);

				dataObject.setSimulation(simulation);
				dataObject.setHdSerial(hdSerial);
				dataObject.setInitialLocalization(initialLocalization);
				dataObject.setTargetName(target);
				dataObject.setRestriction(restriction);
				dataObject.setLanguage(language);
			}
			System.out.println("[WAIProtocolManipulation] Data Object from Client Message returned...");
			
			return dataObject;
		} else {
			System.out.println("[WAIProtocolManipulation] ERROR: An Error occur while trying to" +
					" get the estimated position from message returned from Server: output message null");
			return null;
		}
	}

	/**
	 * Build the message to Estimation Position Server.<br>
	 *  
	 * @see 
	 * 		br.com.wai2008.socket.protocol.ServerToServerProtocol
	 * @see 
	 * 		br.com.wai2008.socket.dataobject.WAIServiceObject
	 * 
	 * @param
	 * 		dataObject WAIServiceObject data object.
	 * 
	 * @return
	 * 		<b>The message</b> to be sent to the estimation position server or<br>
	 * 		<b>null</b> if an error occur while build the message.
	 */
	public static String getMessageToEstimatePositionServer(WAIServiceObject dataObject) {
		System.out.println("[WAIProtocolManipulation] Building Message to the Etimation Position Server...");
		if (dataObject.getHdSerial() != null && dataObject.getNetwork() != null) {
			StringBuilder message = new StringBuilder(ServerToServerProtocol.TAG_SS_ROOT_START);
			message.append(ServerToServerProtocol.TAG_SS_HDSERIAL_START);
			message.append(dataObject.getHdSerial());
			message.append(ServerToServerProtocol.TAG_SS_HDSERIAL_END);
			for (WAINetworkObject network : dataObject.getNetwork()) {
				message.append(ServerToServerProtocol.TAG_SS_NETWORK_START);
				message.append(ServerToServerProtocol.TAG_SS_ID_START);
				message.append(network.getId());
				message.append(ServerToServerProtocol.TAG_SS_ID_END);
				message.append(ServerToServerProtocol.TAG_SS_SIGNAL_START);
				message.append(network.getSignal());
				message.append(ServerToServerProtocol.TAG_SS_SIGNAL_END);
				message.append(ServerToServerProtocol.TAG_SS_NETWORK_END);
			}
			message.append(ServerToServerProtocol.TAG_SS_ROOT_END);
			message.append(ServerToServerProtocol.END_LINE);
			System.out.println("[WAIProtocolManipulation] Message to the Etimation Position Server built...");
			
			return message.toString();
		} else {
			System.out.println("[WAIProtocolManipulation] ERROR: An Error occur while trying to" +
			" build the message to estimated position Server: output message null");
			return null;
		}
	}

	/**
	 * Get the error message from Estimation Position Server.<br>
	 *  
	 * @see 
	 * 		br.com.wai2008.socket.protocol.ClientToServerProtocol
	 * 
	 * @return
	 * 		<b>The message</b> to be sent to the client.
	 */
	public static String getErrorMessageFromEstimatePositionServer() {
		System.out.println("[WAIProtocolManipulation] Getting Error Message from Estimation Position Server...");
		String errorMessage = WAIProtocolManipulation.getErrorProtocolToClient(ClientToServerDefaultMessages.CODE_INTERNAL_ERROR1, 
				ClientToServerDefaultMessages.DESCRIPTION_GETXY_ERROR);
		System.out.println("[WAIProtocolManipulation] Error Message from Estimation Position Server returned...");
		return errorMessage;
	}

	/**
	 * Get the error message from GuiaMenos service.<br>
	 *  
	 * @see 
	 * 		br.com.wai2008.socket.protocol.ClientToServerProtocol
	 * 
	 * @return
	 * 		<b>The message</b> to be sent to the client.
	 */
	public static String getErrorMessageFromGuiaMenos() {
		System.out.println("[WAIProtocolManipulation] Getting Error Message from GuiaMenos...");
		String errorMessage = WAIProtocolManipulation.getErrorProtocolToClient(ClientToServerDefaultMessages.CODE_INTERNAL_ERROR2, 
				ClientToServerDefaultMessages.DESCRIPTION_GETROUTE_ERROR);
		System.out.println("[WAIProtocolManipulation] Error Message from GuiaMenos returned...");
		return errorMessage;
	}

	/**
	 * Get the error message from Client message.<br>
	 *  
	 * @see 
	 * 		br.com.wai2008.socket.protocol.ClientToServerProtocol
	 * 
	 * @return
	 * 		<b>The message</b> to be sent to the client.
	 */
	public static String getErrorMessageFromClientMessage() {
		System.out.println("[WAIProtocolManipulation] Getting Error Message from Client message...");
		String errorMessage = WAIProtocolManipulation.getErrorProtocolToClient(ClientToServerDefaultMessages.CODE_INTERNAL_ERROR3, 
				ClientToServerDefaultMessages.DESCRIPTION_GETMESSAGE_ERROR);
		System.out.println("[WAIProtocolManipulation] Error Message from Client message returned...");
		return errorMessage;
	}
	
	/**
	 * Parse the return message from estimation position service.<br>
	 *  
	 * @see 
	 * 		br.com.wai2008.socket.protocol.ServerToServerProtocol
	 * 
	 * @param
	 * 		message message received from estimation position service.
	 * 		This message is in a ServerToServerProtocol protocol.
	 * 
	 * @return
	 * 		<b>String[0]</b> with x estimated position and <b>String[1]</b> with y 
	 * 		estimated position or<br>
	 * 		<b>null</b> if an error occur while parse the estimated position message 
	 * 		returned.
	 */
	public static String[] getEstimatedPositionFromMessageReturned(String message) {
		System.out.println("[WAIProtocolManipulation] Getting Estimated Position from Message Returned...");
		if (message != null && !message.contains(ServerToServerProtocol.TAG_SS_CODE_START)) {
			int xIndex = message.indexOf(ServerToServerProtocol.TAG_SS_XESTIMADO_START) + 
								ServerToServerProtocol.TAG_SS_XESTIMADO_START.length();
			int yIndex = message.indexOf(ServerToServerProtocol.TAG_SS_YESTIMADO_START) + 
								ServerToServerProtocol.TAG_SS_YESTIMADO_START.length();
			String xEstimado = message.substring(xIndex, 
					message.indexOf(ServerToServerProtocol.TAG_SS_XESTIMADO_END));
			String yEstimado = message.substring(yIndex, 
					message.indexOf(ServerToServerProtocol.TAG_SS_YESTIMADO_END));
			System.out.println("[WAIProtocolManipulation] Estimated Position: x[" + xEstimado + "]; y[" + yEstimado + "]");
			return new String[]{xEstimado, yEstimado};
		} else {
			System.out.println("[WAIProtocolManipulation] ERROR: An Error occur while trying to" +
					" get the estimated position from message returned from Server: output message null");
			return null;
		}
	}

	/**
	 * Build the message to be sent to the client.<br>
	 *  
	 * @see 
	 * 		br.com.wai2008.socket.protocol.ClientToServerProtocol
	 * @see 
	 * 		br.com.wai2008.socket.dataobject.WAIServiceObject
	 * 
	 * @param
	 * 		dataObject WAIServiceObject data object.
	 * 
	 * @return
	 * 		<b>The message</b> to be sent to the client or<br>
	 * 		<b>null</b> if an error occur while build the message.
	 */
	public static String getMessageToClient(WAIServiceObject dataObject) {
		System.out.println("[WAIProtocolManipulation] Building Message to the Client...");
		if (dataObject.getRoute() != null) {
			StringBuilder message = new StringBuilder(ClientToServerProtocol.TAG_SC_ROOT_START);			
			for (Localizacao localizacao : dataObject.getRoute()) {
				message.append(ClientToServerProtocol.TAG_SC_LOCALIZATION_START);
				message.append(ClientToServerProtocol.TAG_SC_X_START);
				message.append(localizacao.getX());
				message.append(ClientToServerProtocol.TAG_SC_X_END);
				message.append(ClientToServerProtocol.TAG_SC_Y_START);
				message.append(localizacao.getY());
				message.append(ClientToServerProtocol.TAG_SC_Y_END);
				message.append(ClientToServerProtocol.TAG_SC_FLOOR_START);
				message.append(localizacao.getAndar());
				message.append(ClientToServerProtocol.TAG_SC_FLOOR_END);
				message.append(ClientToServerProtocol.TAG_SC_LOCALIZATION_END);
			}
			if (dataObject.getMessage() != null || (dataObject.getRoute() != null && dataObject.getRoute().length > 0 && 
					dataObject.getRoute()[0].getDirection() != null)) {
				message.append(ClientToServerProtocol.TAG_SC_MESSAGE_START);
				if (dataObject.getMessage() != null) {
					message.append(dataObject.getMessage());
				}
				if (dataObject.getRoute() != null && dataObject.getRoute().length > 0) {
					message.append(dataObject.getRoute()[0].getDirection());
				} 
				message.append(ClientToServerProtocol.TAG_SC_MESSAGE_END);
			}
			message.append(ClientToServerProtocol.TAG_SC_ROOT_END);
			message.append(ClientToServerProtocol.END_LINE);
			System.out.println("[WAIProtocolManipulation] Message to the Client built...");
			
			return message.toString();
		} else {
			System.out.println("[WAIProtocolManipulation] ERROR: An Error occur while trying to" +
			" build the message to the client: output message null");
			return null;
		}
	}

	/**
	 * Put the code and description for error in the client protocol.<br>
	 *  
	 * @see 
	 * 		br.com.wai2008.socket.protocol.ClientToServerProtocol
	 * 
	 * @param
	 * 		code the error code.
	 * @param
	 * 		description the error description.
	 * 
	 * @return
	 * 		<b>The error message</b> to be sent to the client.
	 */
	private static String getErrorProtocolToClient(String code, String description) {
		String protocol = ClientToServerProtocol.TAG_CS_ROOT_START + ClientToServerProtocol.TAG_SC_CODE_START + 
							code + ClientToServerProtocol.TAG_SC_CODE_END + 
							ClientToServerProtocol.TAG_SC_DESCRIPTION_START + description + 
							ClientToServerProtocol.TAG_SC_DESCRIPTION_END + 
							ClientToServerProtocol.TAG_CS_ROOT_END + ClientToServerProtocol.END_LINE;
		return protocol;
	}
}
